/*--------------------------------------------------------------------------
    This source file is part of Abraxas Game Engine
    For the latest info, see http://code.google.com/abraxasge/
    Copyright (C) 2009, Andrew LeRoy <aleroy@member.igda.org>
    ---

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA  02110-1301, USA.
--------------------------------------------------------------------------*/
#include "AbxStdHeaders.hpp"
#include "AbxOptions.hpp"
#include "AbxString.hpp"

#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/tokenizer.hpp>
#include <boost/token_functions.hpp>

//using boost::program_options;
namespace po = boost::program_options;

namespace Abx
{
    String const OptionsImpl::sDEFAULT_CONFIG_FILE = "AbraxasGE.ini";
    
    OptionsImpl::OptionsImpl() :
        options_("Configuration Options"),
        values_()
    { }
    OptionsImpl::~OptionsImpl()
    { }
    
    bool OptionsImpl::startup(std::vector<String> args)
    {
        po::options_description generic("Generic");
        generic.add_options()
            ("version,v", "print version string")
            ("help,h", "produce help message")    
            ;
            
        // Hidden options command line options will not be shown to the user.
        po::options_description hidden("Hidden");
        hidden.add_options()
            ("config-file,ini", po::value<String>(), "configuration file")
            ;       

        po::options_description engine("Engine");
        engine.add_options()
            ("Engine.LogPath,lp",    po::value<String>(),                       "Location of logs (defaults to '.'")
            ("Engine.PluginPath,pp", po::value<String>(),                       "Location of plugin library files")
            ("Engine.Plugin,p",      po::value<std::vector<String> >()->composing(), "Filename of the Graphics System plugin library")
            ;

        po::options_description opengl("OpenGL");
        opengl.add_options()
            ("OpenGL.Display-Frequency",     po::value<String>(), "(aka: refresh rate)")
            ("OpenGL.FSAA",                  po::value<String>(), "Anti-Aliasing")
            ("OpenGL.Full-Screen",           po::value<String>(), "Full Screen=yes; Windowed=no")
            ("OpenGL.RTT-Preferred-Mode",    po::value<String>(), "floating point precision?")
            ("OpenGL.VSync",                 po::value<String>(), "Helps prevent flicker in windowed mode")
            ("OpenGL.Video-Mode",            po::value<String>(), "Resolution")
            ("OpenGL.sRGB-Gamma-Conversion", po::value<String>(), "")
            ;
                
        po::options_description plugin_gfx("PLUGIN_Graphics");
        plugin_gfx.add_options()
            ("PLUGIN_Graphics.PluginFolder", po::value<String>(),                       "Define plugin folder")
            ("PLUGIN_Graphics.Plugin",       po::value<std::vector<String> >()->composing(), "Ogre plugin filename")
            ("PLUGIN_Graphics.FileSystem",   po::value<std::vector<String> >()->composing(), "Ogre media path")
            ("PLUGIN_Graphics.Zip",          po::value<std::vector<String> >()->composing(), "Ogre media zip")
            ;


        po::options_description cmd_options;
        cmd_options.add(generic).add(hidden);

        options_.add(engine).add(opengl).add(plugin_gfx);

        po::options_description visible;
        visible.add(generic).add(options_);
        
//        po::positional_options_description p;
//        p.add("config-file", -1);
        
        po::variables_map cmd_vm;
        po::store(po::command_line_parser(args).options(cmd_options).run(), cmd_vm);
//            options(cmd_options).positional(p).run(), cmd_vm);
        po::notify(cmd_vm);

        if (cmd_vm.count("help"))
        {
            std::cout << visible << std::endl;
            return false;
        }

        if (cmd_vm.count("version"))
        {
            std::cout << "AbraxasGE " << ABX_VERSION_MAJOR << "." << ABX_VERSION_MINOR
                 << ABX_VERSION_PATCH << ABX_VERSION_SUFFIX << " (" << ABX_VERSION_NAME
                 << ")" << std::endl;
            return false;
        }

        String cfg = cmd_vm["config-file"].empty()
                   ? sDEFAULT_CONFIG_FILE
                   : cmd_vm["config-file"].as<String>();
        std::ifstream ifs(cfg.c_str());

        po::store(po::parse_config_file(ifs, options_), values_);
        po::notify(values_);
        
        return true;
    }
    
    bool OptionsImpl::shutdown()
    {
        return true;
    }
    
    bool OptionsImpl::empty(String const& name)
    {
        return values_[name].empty();
    }

} // namespace Abx
